﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.IO;
using System.Linq;

namespace ChinaColorDisplay
{
    /// <summary>
    /// NewtonJson 扩展
    /// </summary>
    public static class NewtonJsonExtension
    {
        /// <summary>
        /// object转成Json字符串
        /// </summary>
        /// <param name="data">object  需转换的对象</param>
        /// <returns>转换后的Json字符串</returns>
        public static string JsonToString(this object data)
        {
            return JsonConvert.SerializeObject(data);
        }

        /// <summary>
        /// Json字符串转换成对象
        /// </summary>
        /// <typeparam name="T">转成对象的类型</typeparam>
        /// <param name="str">用于转换的Json字符串</param>
        /// <returns>转成后的对象 如果转换出错则抛出异常</returns>
        public static T JsonFromString<T>(this string str)
        {
            T temp = default(T);
            try
            {
                temp = JsonConvert.DeserializeObject<T>(str);
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return temp;
        }

        /// <summary>
        /// Json字符串转换成对象
        /// </summary>
        /// <param name="str">用于转换的Json字符串</param>
        /// <returns>转换后的对象</returns>
        public static object JsonFromString(this string str)
        {
            return JsonConvert.DeserializeObject<object>(str);
        }

        /// <summary>
        /// Json 格式化
        /// </summary>
        /// <param name="jsonStr">未格式化的Json字符串</param>
        /// <returns>格式化后的Json字符串</returns>
        public static string JsonFormatOut(this string jsonStr)
        {
            //格式化json字符串
            JsonSerializer serializer = new JsonSerializer();
            TextReader tr = new StringReader(jsonStr);
            JsonTextReader jtr = new JsonTextReader(tr);
            object obj = serializer.Deserialize(jtr);
            if (obj != null)
            {
                StringWriter textWriter = new StringWriter();
                JsonTextWriter jsonWriter = new JsonTextWriter(textWriter)
                {
                    Formatting = Formatting.Indented,
                    Indentation = 4,
                    IndentChar = ' '
                };
                serializer.Serialize(jsonWriter, obj);
                return textWriter.ToString();
            }
            else
            {
                return jsonStr;
            }
        }

        /// <summary>
        /// 通过Json数据中的key获取对应的Value 重名的获取第一个  暂只支持获取简单类型
        /// </summary>
        /// <typeparam name="T">所获取数据的数据类型</typeparam>
        /// <param name="jObject">JObject对象</param>
        /// <param name="key">key</param>
        /// <returns>key对应的Value  没有找到时返回null</returns>
        public static T GetValueByKey<T>(this JObject jObject, string key)
        {
            var tempValue = jObject.GetValue(key);
            if (tempValue != null)
            {
                return tempValue.Value<T>();
            }
            else
            {
                var enumerator = jObject.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    if (enumerator.Current.Value.HasValues)
                    {
                        if (enumerator.Current.Value is JObject)
                        {
                            T tempTValue = GetValueByKey<T>(enumerator.Current.Value as JObject, key);
                            if (tempTValue != null)
                            {
                                return tempTValue;
                            }
                        }
                        else if (enumerator.Current.Value is JArray)
                        {
                            JArray arrayObj = enumerator.Current.Value as JArray;
                            T tempTValue = GetValueByKey<T>(arrayObj as JArray, key);
                            if (tempTValue != null)
                            {
                                return tempTValue;
                            }
                        }
                    }
                }
            }

            return default(T);
        }

        /// <summary>
        /// 通过Json数据中的key获取对应的Value  数组类型数据 重名的获取第一个 暂只支持获取简单类型
        /// </summary>
        /// <typeparam name="T">所获取数据的数据类型</typeparam>
        /// <param name="arrayObj">JArray对象</param>
        /// <param name="key">key</param>
        /// <returns>key对应的Value  没有找到时返回null</returns>
        public static T GetValueByKey<T>(this JArray arrayObj, string key)
        {
            if (arrayObj != null)
            {
                for (int index = 0; index < arrayObj.Count; ++index)
                {
                    var itemObj = arrayObj[index];
                    if (itemObj is JObject)
                    {
                        T tempTValue = GetValueByKey<T>(itemObj as JObject, key);
                        if (tempTValue != null)
                        {
                            return tempTValue;
                        }
                    }
                    else if (itemObj is JArray)
                    {
                        T tempTValue = GetValueByKey<T>(itemObj as JArray, key);
                        if (tempTValue != null)
                        {
                            return tempTValue;
                        }
                    }
                }

            }
            return default(T);
        }

        /// <summary>
        /// 通过Json数据中的key获取对应的Value 重名的获取第一个
        /// </summary>
        /// <typeparam name="T">所获取数据的数据类型</typeparam>
        /// <param name="jObject">JObject对象</param>
        /// <param name="key">key</param>
        /// <returns>key对应的Value  没有找到时返回null</returns>
        public static T GetValueByKey<T>(this JToken jObject, string key)
        {
            var propChildren = jObject.Children().Cast<JProperty>();
            var matchProp = propChildren.FirstOrDefault(p => p.Name == key);
            if (matchProp != null)
            {
                return jObject.Value<T>(key);
            }

            return default(T);
        }

        /// <summary>
        /// 通过描述路径获取对应的Value
        /// </summary>
        /// <typeparam name="T">所获取数据的数据类型</typeparam>
        /// <param name="jObject">JObject对象</param>
        /// <param name="path">描述路径,key之间通过分割符进行分割</param>
        /// <param name="separator">路径描述中key分割符</param>
        /// <returns>描述路径对的值</returns>
        public static T GetValueByPath<T>(this JObject jObject, string path, params char[] separator)
        {
            if (!string.IsNullOrEmpty(path))
            {
                string[] keys = path.Split(separator);
                JObject ptrJObject = jObject;
                int count = keys.Count();
                for (int index = 0; index < count; ++index)
                {
                    if (ptrJObject != null)
                    {
                        if (index == count - 1)
                        {
                            return ptrJObject.GetValue(keys[index]).Value<T>();
                        }

                        ptrJObject = ptrJObject.GetValue(keys[index]).Value<JObject>();
                    }
                }
            }

            return default(T);
        }


        /// <summary>
        /// 通过描述路径获取对应的Value
        /// </summary>
        /// <typeparam name="T">所获取数据的数据类型</typeparam>
        /// <param name="jObject">JObject对象</param>
        /// <param name="path">描述路径,key之间通过"."进行分割</param>
        /// <returns>描述路径对的值</returns>
        public static T GetValueByPath<T>(this JObject jObject, string path)
        {
            return GetValueByPath<T>(jObject, path, '.');
        }


        /// <summary>
        /// 通过描述路径获取对应的Value
        /// </summary>
        /// <typeparam name="T">所获取数据的数据类型</typeparam>
        /// <param name="jToken">JToken对象</param>
        /// <param name="path">描述路径,key之间通过分割符进行分割</param>
        /// <param name="separator">路径描述中key分割符</param>
        /// <returns>描述路径对的值</returns>
        public static T GetValueByPath<T>(this JToken jToken, string path, params char[] separator)
        {
            if (!string.IsNullOrEmpty(path))
            {
                string[] keys = path.Split(separator);
                JToken ptrJToken = jToken;
                int count = keys.Count();
                for (int index = 0; index < count; ++index)
                {
                    if (ptrJToken != null)
                    {
                        if (index == count - 1)
                        {
                            return ptrJToken.Value<T>(keys[index]);
                        }

                        ptrJToken = ptrJToken.Value<JObject>(keys[index]);
                    }
                }
            }

            return default(T);
        }




        /// <summary>
        /// 判断JToken中是否包含对应的字段或属性
        /// </summary>
        /// <param name="jToken">JToken  对应</param>
        /// <param name="peropertyName">字段或属性名称</param>
        /// <returns></returns>
        public static bool IsContainProp(this JToken jToken, string peropertyName)
        {
            var propChildren = jToken.Children().Cast<JProperty>();
            var matchProp = propChildren.FirstOrDefault(p => p.Name == peropertyName);
            if (matchProp != null)
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// 判断JObject中是否包含对应的字段或属性
        /// </summary>
        /// <param name="jObject">JToken  对应</param>
        /// <param name="peropertyName">字段或属性名称</param>
        /// <returns></returns>
        public static bool IsContainProp(this JObject jObject, string peropertyName)
        {
            var propChildren = jObject.Children().Cast<JProperty>();
            var matchProp = propChildren.FirstOrDefault(p => p.Name == peropertyName);
            if (matchProp != null)
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// 数据拷贝
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="src">源数据</param>
        /// <param name="dst">目标</param>
        public static void PopulateObject<T>(T src, T dst)
        {
            JObject jobject = src.JsonToString().JsonFromString<JObject>();
            JsonReader jObjectReader = jobject.CreateReader();
            JsonSerializer temp = new JsonSerializer();
            temp.Populate(jObjectReader, dst);
        }

        /// <summary>
        /// 数据赋值
        /// </summary>
        /// <param name="dst">目标对象</param>
        /// <param name="jsonStr">json字符串</param>
        public static void PopulateObject(object dst, string jsonStr)
        {
            JObject jobject = jsonStr.JsonFromString<JObject>();
            JsonReader jObjectReader = jobject.CreateReader();
            JsonSerializer temp = new JsonSerializer();
            temp.Populate(jObjectReader, dst);
        }


        /// <summary>
        /// 聚合参数
        /// </summary>
        /// <param name="args">参数</param>
        /// <returns>聚合后的参数</returns>
        public static JObject GatherArgs(params object[] args)
        {
            JObject param = new JObject();
            for (int index = 0; index < args.Length; index += 2)
            {
                try
                {
                    param[args[index]] = new JValue(args[index + 1]);
                }
                catch (Exception)
                {
                    param[args[index]] = (JToken)args[index + 1].JsonToString().JsonFromString();
                }
            }

            return param;
        }
    }
}
